package jscinttools.utilities.jhplotutilities;

import hep.aida.*;
import java.io.*;
import java.lang.*;
import java.text.Format.*;
import java.text.NumberFormat.*;
import java.text.DecimalFormat;
import java.awt.*;
import java.awt.FontMetrics;
import javax.swing.JComponent;

import jhplot.io.*;
import jhplot.jadraw.*;
import jhplot.*;

import jplot.Translate;

import japlot.Global;

/**
 *  Some static methods for HPlotJa Plotter
 *
 *@author     Marc-Antoine Verdier
 *@created    18 septembre 2010
 */
public class HPlotJaUtil
{
	/**
	 *  The main program for the HPlotJaUtil class
	 *
	 *@param  argv  The command line arguments
	 */
	public static void main(String[] argv)
	{
		HPlotJaUtil hpju = new HPlotJaUtil();
		System.out.println("That's all folks !");
	}


	/**
	 *  Constructor for the HPlotJaUtil object
	 */
	public HPlotJaUtil() { }


	/**
	 *  Gets the bestLogAxisLim attribute of the ScintillationAnalysisPlotter_BGO
	 *  object
	 *
	 *@param  theHisto  Description of the Parameter
	 *@return           The bestLogAxisLim value
	 */
	public double[] getBestLogAxisLim(IHistogram1D theHisto)
	{
		double[] axisLim = {0, 0};
		double minLim = theHisto.minBinHeight();
		double maxLim = theHisto.maxBinHeight();
		if (maxLim > 0 && minLim >= 0)
		{
			if (maxLim > 1)
			{
				axisLim[1] = Math.pow(10, Math.floor(Math.log10(maxLim)) + 1);
			}
			else if (maxLim == 1)
			{
				axisLim[1] = 1;
			}
			else if (maxLim < 1)
			{
				axisLim[1] = Math.pow(10, -1 * (Math.ceil(Math.log10(maxLim))));
			}
			//System.out.println("axisLim[1]=" + axisLim[1]);

			if (minLim > 1)
			{
				axisLim[0] = Math.pow(10, Math.floor(Math.log10(minLim)));
			}
			else if (minLim < 1 && minLim > 0)
			{
				axisLim[0] = Math.pow(10, -1 * Math.ceil(Math.abs(Math.log10(minLim))));
			}
			else if (minLim == 1)
			{
				axisLim[0] = 0.1;
			}
			else
			{
				axisLim[0] = Math.pow(10, Math.log10(axisLim[1]) - 5);
			}
			//System.out.println("axisLim[0]=" + axisLim[0]);
		}
		else
		{
			axisLim[0] = 0.1;
			axisLim[1] = 1;
		}
		return axisLim;
	}


	/**
	 *  Gets the bestLogAxisLim attribute of the ScintillationAnalysisPlotter_BGO
	 *  object
	 *
	 *@param  theDPS  Description of the Parameter
	 *@param  coord   Description of the Parameter
	 *@return         The bestLogAxisLim value
	 */
	public double[] getBestLogAxisLim(IDataPointSet theDPS, int coord)
	{
		double[] axisLim = {0, 0};
		double minLim = theDPS.lowerExtent(coord);
		double maxLim = theDPS.upperExtent(coord);
		if (maxLim > 0 && minLim >= 0)
		{
			if (maxLim > 1)
			{
				axisLim[1] = Math.pow(10, Math.floor(Math.log10(maxLim)) + 1);
			}
			else if (maxLim == 1)
			{
				axisLim[1] = 1;
			}
			else if (maxLim < 1)
			{
				axisLim[1] = Math.pow(10, -1 * (Math.ceil(Math.log10(maxLim))));
			}
			//System.out.println("axisLim[1]=" + axisLim[1]);

			if (minLim > 1)
			{
				axisLim[0] = Math.pow(10, Math.floor(Math.log10(minLim)));
			}
			else if (minLim < 0.9999 && minLim > 0)
			{
				axisLim[0] = Math.pow(10, -1 * Math.ceil(Math.abs(Math.log10(minLim))));
			}
			else if (minLim == 1 || (minLim < 1 && minLim >= 0.9999))
			{
				axisLim[0] = 0.8;
			}
			else
			{
				axisLim[0] = Math.pow(10, Math.log10(axisLim[1]) - 5);
			}
			//System.out.println("axisLim[0]=" + axisLim[0]);
		}
		else
		{
			axisLim[0] = 0.1;
			axisLim[1] = 1;
		}
		return axisLim;
	}


	/**
	 *  Gets the bestLogAxisLim attribute of the ScintillationAnalysisPlotter_BGO
	 *  object
	 *
	 *@param  theVal  Description of the Parameter
	 *@return         The bestLogAxisLim value
	 */
	public double[] getBestLogAxisLim(double[][] theVal)
	{
		double[] axisLim = {0, 0};
		double minVal = theVal[0][0];
		double maxVal = theVal[0][0];
		for (int i = 0; i < theVal.length; i++)
		{
			for (int j = 0; j < theVal[0].length; j++)
			{
				if (theVal[i][j] < minVal)
				{
					minVal = theVal[i][j];
				}
				if (theVal[i][j] > maxVal)
				{
					maxVal = theVal[i][j];
				}
			}
		}
		axisLim[0] = minVal;
		axisLim[1] = maxVal;
		return axisLim;
	}


	/**
	 *  Gets the bestLinAxisLimMax attribute of the
	 *  ScintillationAnalysisPlotter_BGO object
	 *
	 *@param  theHisto  Description of the Parameter
	 *@return           The bestLinAxisLimMax value
	 */
	public double getBestLinAxisLimMax(H1D theHisto)
	{
		double axisLim = 0;
		double hMax = theHisto.maxBinHeight();
		//System.out.println("hMax = " + hMax);
		double dec = Math.pow(10, Math.floor(Math.abs(Math.log10(hMax))));
		//double dec = Math.abs(Math.log10(hMax));
		//System.out.println("dec = " + dec);
		double base = Math.floor(hMax / (double) dec);
		//System.out.println("base = " + base);
		if ((hMax / (double) dec) < (base + 0.5))
		{
			axisLim = (base + 1) * dec;
		}
		else
		{
			axisLim = (base + 1.5) * dec;
		}
		//System.out.println("axisLim = " + axisLim);
		return axisLim;
	}


	/**
	 *  Description of the Method
	 *
	 *@param  theString  Description of the Parameter
	 *@return            Description of the Return Value
	 */
	public String[] changeUnderscores(String[] theString)
	{
		for (int i = 0; i < theString.length; i++)
		{
			//System.out.println("old String = " + theString[i]);
			theString[i] = theString[i].replaceAll("_", " ");
			//System.out.println("new String = " + theString[i]);
		}
		return theString;
	}


	/**
	 *  Description of the Method
	 *
	 *@param  theVal  Description of the Parameter
	 *@return         Description of the Return Value
	 */
	public double[] roundValuesTo3Digit(double[] theVal)
	{

		for (int i = 0; i < theVal.length; i++)
		{
			//System.out.println("theVal before = " + theVal[i]);
			double dec = 0.0;
			if (theVal[i] > 1)
			{
				dec = Math.pow(10, (long) Math.floor(Math.log10(Math.abs(theVal[i]))));
			}
			else
			{
				dec = Math.pow(10, (long) Math.ceil(Math.log10(Math.abs(theVal[i]))));
			}
			//System.out.println("dec = " + dec);
			long roundVal = Math.round((theVal[i] / (double) dec) * 100.0);
			//System.out.println("roundVal = " + roundVal);
			theVal[i] = roundVal / 100.0 * dec;
			//System.out.println("theVal after = " + theVal[i]);
		}
		return theVal;
	}


	/**
	 *  Description of the Method
	 *
	 *@param  theVal  Description of the Parameter
	 *@return         Description of the Return Value
	 */
	public double[] roundValuesTo3DigitString(double[] theVal)
	{
		//String[] theValString = new String[theVal.length];
		for (int i = 0; i < theVal.length; i++)
		{
			//if (theVal[i] >= 100)
			//{
			DecimalFormat fmt = new DecimalFormat("#.###");
			//}
			//if (theVal[i] >= 10 && theVal[i]<100)
			//{
			//	DecimalFormat fmt = new DecimalFormat("#.###");
			//}
			//if (theVal[i] >= 1 && theVal[i]<10)
			//{
			//	DecimalFormat fmt = new DecimalFormat("#.###");
			//}
			//if (theVal[i] >= 100)
			//{
			//	DecimalFormat fmt = new DecimalFormat("#.###");
			//}
			theVal[i] = Double.parseDouble(fmt.format(theVal[i]));
		}
		return theVal;
	}


	/**
	 *  Description of the Method
	 *
	 *@param  theVal  Description of the Parameter
	 *@return         Description of the Return Value
	 */
	public double roundValuesTo3Digit(double theVal)
	{
		double dec = 0.0;
		//System.out.println("theVal before = " + theVal);
		if (theVal > 1)
		{
			dec = Math.pow(10, (long) Math.floor(Math.log10(Math.abs(theVal))));
		}
		else
		{
			dec = Math.pow(10, (long) Math.ceil(Math.log10(Math.abs(theVal))));
		}
		long roundVal = Math.round((theVal / (double) dec) * 100.0);
		theVal = roundVal / 100.0 * dec;
		//System.out.println("theVal after = " + theVal);
		return theVal;
	}


	/**
	 *  Gets the size of a label
	 *
	 *@param  theLabel    the JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 *@return             The size of the label
	 */
	public static double[] getLabelSize(JaText theLabel, HPlotJa thePlotter)
	{
		FontMetrics fm = thePlotter.getFontMetrics(theLabel.getFont());
		String stext = Translate.shrink(theLabel.getText());
		int width = fm.stringWidth(stext);
		int height = fm.getHeight();
		double[] size = {Global.toX(width), Global.toY(height)};
		return size;
	}


	/**
	 *  Gets the width of a label
	 *
	 *@param  theLabel    the JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 *@return             The width of the label
	 */
	public static double getLabelWidth(JaText theLabel, HPlotJa thePlotter)
	{
		FontMetrics fm = thePlotter.getFontMetrics(theLabel.getFont());
		String stext = Translate.shrink(theLabel.getText());
		int width = fm.stringWidth(stext);
		int height = fm.getHeight();
		return Global.toX(width);
	}


	/**
	 *  Gets the height of a label
	 *
	 *@param  theLabel    the JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 *@return             The height of the label
	 */
	public static double getLabelHeight(JaText theLabel, HPlotJa thePlotter)
	{
		FontMetrics fm = thePlotter.getFontMetrics(theLabel.getFont());
		String stext = Translate.shrink(theLabel.getText());
		int width = fm.stringWidth(stext);
		int height = fm.getHeight();
		return Global.toY(height);
	}


	///**
	// *  Description of the Method
	// *
	// *@param  thePlotter  Description of the Parameter
	// *@return             Description of the Return Value
	// */
	//public static double[] marginsSizeNDC(HPlotJa thePlotter)
	//{
	//	double[] margins = {0.1, 0.1, 0.1, 0.1};
	//	int nX = thePlotter.getNtoX();
	//	int nY = thePlotter.getNtoY();
	//	//JaAxes[] theAxes = new JaAxes[nX * nY];
	//	double[] width = new double[nX];
	//	double[] height = new double[nY];
	//	for (int i = 0; i < nX; i++)
	//	{
	//		for (int j = 0; j < nY; j++)
	//		{
	//			thePlotter.cd(i, j);
	//			theAxes[i] = getPad();
	//		}
	//	}
	//}


	/**
	 *  Sets the label at the center of its axis
	 *
	 *@param  axis        The Axis (0 for X, 1 for Y)
	 *@param  theLabel    The JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 *@param  axisDist    The additional shift on Y (if X axis) or X (if Y axis)
	 */
	public static void setLabelLocationAtCenter(int axis, JaText theLabel, HPlotJa thePlotter, double axisDist)
	{
		double[] theSize = getLabelSize(theLabel, thePlotter);
		if (axis == 0)
		{
			theLabel.setLocation(0.5 - 0.5 * theSize[0], 1 - axisDist, "NDC");
		}
		if (axis == 1)
		{
			theLabel.setLocation(axisDist + theSize[1], 0.5 + 0.5 * theSize[0] * thePlotter.getSizeX() / thePlotter.getSizeY(), "NDC");
		}
	}


	//public static void setLabelLocationAtCenter(int axis, JaText theLabel, HPlotJa thePlotter, double axisDist)
	//{
	//	double[] theSize = getLabelSize(theLabel, thePlotter);
	//	if (axis == 0)
	//	{
	//		theLabel.setLocation(0.5 - 0.5 * theSize[0], 1 - (axisDist + thePlotter.getMarginBottom() - 0.5 * theSize[1]), "NDC");
	//	}
	//	if (axis == 1)
	//	{
	//		theLabel.setLocation(axisDist + thePlotter.getMarginLeft() - 0.5 * theSize[1], 0.5 + 0.5 * theSize[0], "NDC");
	//	}
	//}


	/**
	 *  Sets the label at the center of its axis
	 *
	 *@param  axis        The Axis (0 for X, 1 for Y)
	 *@param  theLabel    The JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 */
	public static void setLabelLocationAtCenter(int axis, JaText theLabel, HPlotJa thePlotter)
	{
		double height = getLabelHeight(theLabel, thePlotter);
		//System.out.println("MarginBottom = " + thePlotter.getMarginBottom());
		//System.out.println("MarginLeft = " + thePlotter.getMarginLeft());
		if (axis == 0)
		{
			setLabelLocationAtCenter(axis, theLabel, thePlotter, (thePlotter.getMarginBottom() - height) * thePlotter.getSizeX() / thePlotter.getSizeY() / 2.0);
		}
		if (axis == 1)
		{
			setLabelLocationAtCenter(axis, theLabel, thePlotter, ((thePlotter.getMarginLeft() / 2.0) - height) * thePlotter.getSizeY() / thePlotter.getSizeX());
		}
	}


	//public static void setLabelLocationAtCenter(int axis, JaText theLabel, HPlotJa thePlotter)
	//{
	//	if (axis == 0)
	//	{
	//		setLabelLocationAtCenter(axis, theLabel, thePlotter, (thePlotter.getMarginBottom() / -2.0));
	//	}
	//	if (axis == 1)
	//	{
	//		setLabelLocationAtCenter(axis, theLabel, thePlotter, (thePlotter.getMarginLeft() / -2.0));
	//	}
	//}


	/**
	 *  Sets the label at the quarter of the canvas. Useful for 1x2, 2x1 or 2x2
	 *  plots
	 *
	 *@param  axis        The Axis (0 for X, 1 for Y)
	 *@param  quarter     The coordinate of the plot in the canvas
	 *@param  theLabel    The JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 *@param  axisDist    The additional shift on Y (if X axis) or X (if Y axis)
	 */
	public static void setLabelLocationAtQuarter(int axis, int[] quarter, JaText theLabel, HPlotJa thePlotter, double axisDist)
	{
		double[] theSize = getLabelSize(theLabel, thePlotter);
		if (axis == 0)
		{
			theLabel.setLocation((0.5 * quarter[0]) + 0.25 - 0.5 * theSize[0], 0.5 + (0.5 * quarter[1]) - (axisDist + thePlotter.getMarginBottom() - 0.5 * theSize[1]), "NDC");
		}
		if (axis == 1)
		{
			theLabel.setLocation(axisDist + thePlotter.getMarginLeft() - 0.5 * theSize[1] + (0.5 * quarter[1]), 0.25 + (0.5 * quarter[0]) + 0.5 * theSize[0], "NDC");
		}
	}


	/**
	 *  Sets the label at the quarter of the canvas. Useful for 1x2, 2x1 or 2x2
	 *  plots
	 *
	 *@param  axis        The Axis (0 for X, 1 for Y)
	 *@param  quarter     The coordinate of the plot in the canvas
	 *@param  theLabel    The JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 */
	public static void setLabelLocationAtQuarter(int axis, int[] quarter, JaText theLabel, HPlotJa thePlotter)
	{
		if (axis == 0)
		{
			setLabelLocationAtQuarter(axis, quarter, theLabel, thePlotter, (thePlotter.getMarginBottom() / -2.0));
		}
		if (axis == 1)
		{
			setLabelLocationAtQuarter(axis, quarter, theLabel, thePlotter, (thePlotter.getMarginLeft() / -2.0));
		}
	}


	/**
	 *  Sets the title of a plot from a multiplot canvas at its center. Useful for
	 *  2x1 or 2x2 plots
	 *
	 *@param  half        The half of the canvas where the plot is located
	 *@param  theLabel    The JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 *@param  topDist     The additional shift
	 */
	public static void setTitleLocationAtQuarter(int half, JaText theLabel, HPlotJa thePlotter, double topDist)
	{
		double[] theSize = getLabelSize(theLabel, thePlotter);
		theLabel.setLocation((0.5 * half) + 0.25 - 0.5 * theSize[0], (1.0 * topDist + thePlotter.getMarginTop() - 0.5 * theSize[1]), "NDC");
	}


	/**
	 *  Sets the title of a plot from a multiplot canvas at its center. Useful for
	 *  2x1 or 2x2 plots
	 *
	 *@param  half        The half of the canvas where the plot is located
	 *@param  theLabel    The JaText containing the label
	 *@param  thePlotter  The HPlotJa plotter on which it is applied
	 */
	public static void setTitleLocationAtQuarter(int half, JaText theLabel, HPlotJa thePlotter)
	{
		setTitleLocationAtQuarter(half, theLabel, thePlotter, (thePlotter.getMarginTop() / -2.0));
	}


	/**
	 *  Removes the tick labels on all the axes
	 *
	 *@param  theAxes  The JaAxes on which it is applied
	 */
	public static void removeTickLabel(JaAxes theAxes)
	{
		String[][] tLab = theAxes.getTicLabel();
		for (int i = 0; i < tLab.length; i++)
		{
			for (int j = 0; j < tLab[i].length; j++)
			{
				tLab[i][j] = "";
			}
		}
		theAxes.setTicLabel(tLab);
	}


	/**
	 *  Removes the tick labels on a particular axis
	 *
	 *@param  axis     The Axis (0 for X, 1 for Y)
	 *@param  theAxes  The JaAxes on which it is applied
	 */
	public static void removeTickLabel(int axis, JaAxes theAxes)
	{
		String[][] tLab = theAxes.getTicLabel();
		for (int i = 0; i < tLab[axis].length; i++)
		{
			tLab[axis][i] = "";
		}
		theAxes.setTicLabel(tLab);
	}


	/**
	 *  Displays 1 as 10^0 on a particular axis
	 *
	 *@param  axis     The Axis (0 for X, 1 for Y)
	 *@param  theAxes  The JaAxes on which it is applied
	 */
	public static void setTickLabelOneToPower(int axis, JaAxes theAxes)
	{
		String[][] tLab = theAxes.getTicLabel();
		for (int i = 0; i < tLab[axis].length; i++)
		{
			if (tLab[axis][i].equals("1"))
			{
				tLab[axis][i] = "10^{0}";
			}
		}
		theAxes.setTicLabel(tLab);
	}



	/**
	 *  Displays 1 as 10^0 on all the axes
	 *
	 *@param  theAxes  The JaAxes on which it is applied
	 */
	public static void setTickLabelOneToPower(JaAxes theAxes)
	{
		String[][] tLab = theAxes.getTicLabel();
		for (int i = 0; i < tLab.length; i++)
		{
			for (int j = 0; j < tLab[i].length; j++)
			{
				if (tLab[i][j].equals("1"))
				{
					tLab[i][j] = "10^{0}";
				}
			}
		}
		theAxes.setTicLabel(tLab);
	}


	/**
	 *  Removes the minus symbol in front of 0 on a particular axis
	 *
	 *@param  axis     The Axis (0 for X, 1 for Y)
	 *@param  theAxes  The JaAxes on which it is applied
	 */
	public static void setTickLabelZeroPositive(int axis, JaAxes theAxes)
	{
		String[][] tLab = theAxes.getTicLabel();
		for (int i = 0; i < tLab[axis].length; i++)
		{
			if (tLab[axis][i].equals("-0"))
			{
				tLab[axis][i] = "0";
			}
		}
		theAxes.setTicLabel(tLab);
	}


	/**
	 *  Removes the minus symbol in front of 0 on all the axes
	 *
	 *@param  theAxes  The JaAxes on which it is applied
	 */
	public static void setTickLabelZeroPositive(JaAxes theAxes)
	{
		String[][] tLab = theAxes.getTicLabel();
		for (int i = 0; i < tLab.length; i++)
		{
			for (int j = 0; j < tLab[i].length; j++)
			{
				if (tLab[i][j].equals("-0"))
				{
					tLab[i][j] = "0";
				}
			}
		}
		theAxes.setTicLabel(tLab);
	}
}

